﻿using Common.Communication;
using Common.Tool.DataTools;
using DeviceBase.Enums;
using DeviceBase.Interfaces;
using DeviceBase.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JueYuanNaiYa.Core.TongHui
{
    public class TH9201BSerialPort:SerialPortBase, IJueYuanNaiYa
    {
        public string Name { get; set; }
        public TH9201BSerialPort(string name, string portName, int baudRate = 115200, int timeout = 1000) : base(portName, baudRate, timeout: timeout)
        {
            Name = name;
        }
        public Result<bool> NewTest(int steps)
        {
            Result<bool> result = new Result<bool>();
            AppendInfo(Name, $"新增测试方案");
            var command = CmdNew(steps);
            var re = WriteThenRead(command);
            if (!re.IsSucceed || !re.Value.SequenceEqual(CmdSetOk))
            {
                result.IsSucceed = false;
                result.Err = "新增测试方案失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, "新增测试方案成功");
            return result.EndTime();
        }

        public Result<bool> SetBeep(bool isOn)
        {
            Result<bool> result = new Result<bool>();
            AppendInfo(Name, $"设置蜂鸣器{isOn}");
            var command = CmdSetBeep(isOn ? "ON" : "OFF");
            var re = Write(command);
            if (!re.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "设置蜂鸣器失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            Thread.Sleep(100);
            command = CmdGetBeep;
            //发送指令并返回
            var re2 = WriteThenRead(command);
            if (!re2.IsSucceed || !re2.Value.Contains(isOn ? "ON" : "OFF"))
            {
                result.IsSucceed = false;
                result.Err = "设置蜂鸣器失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, "设置蜂鸣器成功");
            return result.EndTime();
        }


        public Result<bool> SetTest(JueYuanNaiYaEnum.JueYuanNaiYaMode mode, int step, 
            double vol, double upTime, double downTime, double keepTime,
            double min,double max,
            int freq = 0, double arc = 0)
        {
            Result<bool> result = new Result<bool>();
            AppendInfo(Name, $"设置测试参数");
            AppendInfo(Name, $"步骤检查{step}");
            var command = CmdGetStep;
            var re = WriteThenRead(command);
            if (!re.IsSucceed || re.Value.Count(o => o == ',') != step)
            {
                result.IsSucceed = false;
                result.Err = "步骤检查失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            string type = "";
            switch (mode)
            {
                case JueYuanNaiYaEnum.JueYuanNaiYaMode.绝缘电阻:
                    type = "IR";
                    break;
                case JueYuanNaiYaEnum.JueYuanNaiYaMode.直流耐压:
                    type = "DC";
                    break;
                case JueYuanNaiYaEnum.JueYuanNaiYaMode.交流耐压:
                    type = "AC";
                    break;
                default:
                    break;
            }
            if (type == "AC")
            {
                AppendInfo(Name, $"设置频率{freq}Hz");
                command = CmdFreq(freq,step);
                var re1 = Write(command);
                if (!re1.IsSucceed)
                {
                    result.IsSucceed = false;
                    result.Err = "设置频率失败";
                    AppendResult(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(100);
                command = CmdGetFreq(step);
                re = WriteThenRead(command);
                if (!re.IsSucceed || !int.TryParse(re.Value, out int va) || va != freq)
                {
                    result.IsSucceed = false;
                    result.Err = "设置频率失败";
                    AppendResult(Name, result.Err);
                    return result.EndTime();
                }
                AppendInfo(Name, $"设置电弧{arc}A");
                command = CmdArc(arc, step);
                re1 = Write(command);
                if (!re1.IsSucceed)
                {
                    result.IsSucceed = false;
                    result.Err = "设置电弧失败";
                    AppendResult(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(100);
                command = CmdGetArc(step);
                re = WriteThenRead(command);
                if (!re.IsSucceed || !double.TryParse(re.Value, out double val) || val != arc)
                {
                    result.IsSucceed = false;
                    result.Err = "设置电弧失败";
                    AppendResult(Name, result.Err);
                    return result.EndTime();
                }
            }
            AppendInfo(Name, $"设置电压{vol}V");
            command = CmdSetVol(vol, step, type);
            var re2 = Write(command);
            if (!re2.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "设置电压失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            Thread.Sleep(100);
            command = CmdGetVol(step, type);
            re = WriteThenRead(command);
            if (!re.IsSucceed || !double.TryParse(re.Value, out double v) || v != vol)
            {
                result.IsSucceed = false;
                result.Err = "设置电压失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, $"设置上升时间{upTime}s");
            command = CmdUpTime(upTime, step, type);
            re2 = Write(command);
            if (!re2.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "设置上升时间失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            Thread.Sleep(100);
            command = CmdGetUpTime(step, type);
            re = WriteThenRead(command);
            if (!re.IsSucceed || !double.TryParse(re.Value, out double ut) || ut != upTime)
            {
                result.IsSucceed = false;
                result.Err = "设置上升时间失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, $"设置保持时间{keepTime}s");
            command = CmdKeepTime(keepTime, step, type);
            re2 = Write(command);
            if (!re2.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "设置保持时间失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            Thread.Sleep(100);
            command = CmdGetKeepTime(step, type);
            re = WriteThenRead(command);
            if (!re.IsSucceed || !double.TryParse(re.Value, out double kt) || kt != keepTime)
            {
                result.IsSucceed = false;
                result.Err = "设置保持时间失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, $"设置下降时间{downTime}s");
            command = CmdDownTime(downTime, step, type);
            re2 = Write(command);
            if (!re2.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "设置下降时间失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            Thread.Sleep(100);
            command = CmdGetDownTime(step, type);
            re = WriteThenRead(command);
            if (!re.IsSucceed || !double.TryParse(re.Value, out double dt) || dt != downTime)
            {
                result.IsSucceed = false;
                result.Err = "设置下降时间失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, $"设置上限{max}");
            command = CmdMax(max, step, type);
            re2 = Write(command);
            if (!re2.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "设置上限失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            Thread.Sleep(100);
            command = CmdGetMax(step, type);
            re = WriteThenRead(command);
            if (!re.IsSucceed || !double.TryParse(re.Value, out double ma) || ma != max)
            {
                result.IsSucceed = false;
                result.Err = "设置上限失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, $"设置下限{min}");
            command = CmdMin(min, step, type);
            re2 = Write(command);
            if (!re2.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "设置下限失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            Thread.Sleep(100);
            command = CmdGetMin(step, type);
            re = WriteThenRead(command);
            if (!re.IsSucceed || !double.TryParse(re.Value, out double mi) || mi != min)
            {
                result.IsSucceed = false;
                result.Err = "设置下限失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            AppendInfo(Name, $"设置测试参数成功");
            return result.EndTime();
        }

        public Result<List<JueYuanNaiYaResult>> StartTest(int timeout)
        {
            Result<List<JueYuanNaiYaResult>> result = new Result<List<JueYuanNaiYaResult>>();
            AppendInfo(Name, $"开始测试");
            List<string> temps = new List<string>();
            List<string> vols = new List<string>();
            List<string> units = new List<string>();
            var command = CmdGetStep;
            var re = WriteThenRead(command);
            if (!re.IsSucceed || re.Value.Contains(','))
            {
                result.IsSucceed = false;
                result.Err = "获取步骤失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            var types = re.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < types.Length; i++)
            {
                command = CmdGetVol(i + 1, temps[i]);
                re = WriteThenRead(command);
                if (!re.IsSucceed || !double.TryParse(re.Value, out double v))
                {
                    result.IsSucceed = false;
                    result.Err = "获取设置电压失败";
                    AppendResult(Name, result.Err);
                    return result.EndTime();
                }
                vols.Add(v + "V");
                switch (types[i])
                {
                    case "1": temps.Add("AC"); units.Add("uA"); break;//AC uA
                    case "2": temps.Add("DC"); units.Add("uA"); break;//DC uA
                    case "3": temps.Add("IR"); units.Add("MΩ"); break;//IR MΩ
                    default:
                        temps.Add(""); break;
                }
            }
            command = CmdStart;
            var re2 = Write(command);
            if (!re2.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "开始测试失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            DateTime testTime = DateTime.Now.AddSeconds(timeout);
            while (DateTime.Now < testTime)
            {
                Thread.Sleep(500);
                if (DeviceBase.DeviceServer.IsStop)
                {
                    Write(CmdStop);
                    result.IsSucceed = false;
                    result.Err = "停止测试";
                    AppendResult(Name, result.Err);
                    return result.EndTime();
                }
                //todo 失败停止
            }
            command = CmdFetch;
            re = WriteThenRead(command);
            if (!re.IsSucceed || !re.Value.Contains(","))
            {
                Write(CmdStop);
                result.IsSucceed = false;
                result.Err = "测试失败";
                AppendResult(Name, result.Err);
                return result.EndTime();
            }
            //Judge,Judge1,Judge2,…Judgen,Data1, Data 2,…, Datan 
            var value = re.Value.Substring(2).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < value.Length/2; i ++)
            {
                JueYuanNaiYaResult jueYuanNai = new JueYuanNaiYaResult()
                {
                    type = types[i] == "1" ? "AC" : types[i] == "2" ? "DC" : "IR",
                    value =  vols[i] + "," + value[value.Length / 2 + i] + units[i] ,
                    isPass = value[i] == "1"
                };
                result.Value.Add(jueYuanNai);
                AppendResult(Name, jueYuanNai.type + "," + jueYuanNai.value + "," + jueYuanNai.isPass);
            }
            result.IsSucceed = result.Value.Count(o => o.isPass == false) == 0;
            if (!result.IsSucceed) 
                re.Err = "测试未通过";
            return result.EndTime();
        }

        public Result<bool> StopTest()
        {
            Result<bool> result = new Result<bool>();
            AppendInfo(Name, $"停止测试");
            List<string> temps = new List<string>();
            var command = CmdStop;
            var re = Write(command);
            if (!re.IsSucceed)
            {
                result.IsSucceed = false;
                result.Err = "停止测试失败";
                AppendResult(Name, result.Err);
            }
            AppendInfo(Name, $"停止测试成功");
            return result.EndTime();
        }
        public double IrVolMin = 0.05f;
        public double IrVolMax = 1;
        public double TimeMin = 0.1f;
        public double TimeMax = 999.9f;
        public double IrMin = 0.01f;
        public double IrMax = 10000;
        public double DcwVolMin = 0.05f;
        public double DcwVolMax = 6f;
        public double DcwMin = 0.0001f;
        public double DcwMax = 5;
        public double AcwVolMin = 0.05f;
        public double AcwVolMax = 5f;
        public double AcwMin = 0.001f;
        public double AcwMax = 10;
        string CmdId => "*IDN?\n";
        string CmdNew(int step) => $":SOUR:SAFE:NEW {step}\n";
        string CmdSetOk => "1";
        string CmdGetStep => ":SOUR:SAFE:FUNC?\n";
        string CmdSetBeep(string beep) { return ":SYST:BEEP " + beep + "\n"; }
        string CmdGetBeep => ":SYST:BEEP?\n";
        string CmdSetVol(double vol, int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":LEV " + vol + "\n"; }
        string CmdGetVol(int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":LEV?\n"; }
        string CmdUpTime(double upTime, int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":TIME:RAMP " + upTime + "\n"; }
        string CmdGetUpTime(int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":TIME:RAMP?\n"; }
        string CmdKeepTime(double keepTime, int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":TIME:TEST " + keepTime + "\n"; }
        string CmdGetKeepTime(int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":TIME:TEST?\n"; }
        string CmdDownTime(double downTime, int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":TIME:FALL " + downTime + "\n"; }
        string CmdGetDownTime(int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":TIME:FALL?\n"; }
        string CmdFreq(int freq, int step) { return ":SOUR:SAFE:STEP " + step + ":AC:TIME:FREQ " + freq + "\n"; }
        string CmdGetFreq(int step) { return ":SOUR:SAFE:STEP " + step + ":AC:TIME:FREQ?\n"; }
        string CmdArc(double arc, int step) { return ":SOUR:SAFE:STEP " + step + ":AC:LIM:ARC " + arc + "\n"; }
        string CmdGetArc(int step) { return ":SOUR:SAFE:STEP " + step + ":AC:LIM:ARC?\n"; }
        string CmdMax(double max, int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":LIM:HIGH " + max + "\n"; }
        string CmdGetMax(int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + ":LIM:HIGH?\n"; }
        string CmdMin(double min, int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + "LIM:LOW " + min + "\n"; }
        string CmdGetMin(int step, string type) { return ":SOUR:SAFE:STEP " + step + ":" + type + "LIM:LOW?\n"; }
        string CmdStart => ":SOUR:SAFE:START\n";
        string CmdStop => ":SOUR:SAFE:STOP\n";
        string CmdFetch => ":TEST:FETCH?\n";
    }
}
